local skynet = require "skynet"
local filelog = require "filelog"
local cluster = require "skynet.cluster"
local slottool = require "slottool"
local base = require "base"
local timetool = require "timetool"
local tabletool = require "tabletool"

local robotmgr = {
	CMD = {},
	handler = {},
    robotpool = {},         --机器人池，从robot节点获取500个，缓存在本节点
    robotinfo_list = {},    --运行中机器人的robotinfo数组
    create_robotpool = {},
    is_runrobot = true,
    max_robot_num = 80,     --最大机器人数
    min_robot_num = 10,     --最小机器人
    base_robot_num = 20,    --机器人基础值
    robot_inc_factor = 0.2, --机器人增加系数
    table_robot_num = 10,   --
}

--[[
    AI 埋雷条件：等待上庄不足三人
    埋雷金额10-50之间10的倍数值
    更换AI：金额不足10元,埋雷次数大于10次,每埋一次雷增加10%的离场概率
    其它：10轮还未轮到自己主动下庄,概率抢自己埋的红包
    保护：系统亏损大于1万时，停止AI埋雷
--]]

--当前机器人数
local cur_robot_num = 0

--机器人列表
local robot_list = {}

--创建机器人
function robotmgr.cretae_robot(obj, base_diamond)
    obj = obj or {}
    local robotinfo = robotmgr.handler.get_robotinfo()
    if not robotinfo then
        return
    end
    local logo = robotinfo.logo or "1"
    local sex = robotinfo.sex or base.get_random(1,2)
    local rid = robotinfo.rid or base.get_random(111111,999999)
    local rolename = robotinfo.rolename or "_g" .. rid
    obj.roledata = {
        info = { 
            rolename = rolename,    --名字
            level = 99,             --等级
            logo = logo,            --头像
            sex = sex,              --性别
            rid = rid,
            },
        money = {
            diamond = 0,
            coin = 0,
            lock_coin = 0,
            lock_diamond = 0,
        },
        gps_addr = robotinfo.gps_addr,
        ip_addr = robotinfo.ip_addr,
        is_robot = true,
        table_address = -1,
        already_game_num = 0,
    }
    obj.rid = rid
    --随机diamond
    --local min = base_diamond * 2
    local min = 500
    --local max = base_diamond * 10
    local max = 1000
    obj.roledata.money.diamond = base.get_random(min,max) * 100
    --保存机器人
    robot_list[rid] = 0
    if robotmgr.create_robotpool[rid] == nil then
        robotmgr.create_robotpool[rid] = tabletool.deepcopy(obj)
    end
    --保存robotinfo，方便回收
    robotmgr.robotinfo_list[rid] = robotinfo
    return obj
end

function robotmgr.handler.gen_robotinfo(robot_num)
	local status,result = skynet.pcall(cluster.call, "robotnode", ".router", "gen_robotinfo", robot_num)
    if status and result then
        for _,robotinfo in pairs(result) do
            table.insert(robotmgr.robotpool, robotinfo)
        end
        return true
    else
    	return false
    end
end

function robotmgr.handler.get_robotinfo()
    if not robotmgr.robotpool or #(robotmgr.robotpool) < 1 then
        return nil
    end
    local len = #(robotmgr.robotpool)
    local idx = math.random(1,len)
    local robotinfo = robotmgr.robotpool[idx]
    robotmgr.robotpool[idx] = robotmgr.robotpool[len]
    robotmgr.robotpool[len] = nil
    return robotinfo
end

function robotmgr.handler.save_robotinfos()
    local robot_infos = {}
    for _, robot_info in pairs(robotmgr.robotpool) do
        table.insert(robot_infos, robot_info)
    end
    local status,result = skynet.pcall(cluster.call, "robotnode", ".router", "save_robotinfo", robot_infos)
end

--添加机器人到桌子
function robotmgr.add_robot_to_table(table_service, table_index, robot_num, base_diamond)
    robot_num = robot_num or 1
    for i = 1,robot_num do
        local robot = robotmgr.cretae_robot({}, base_diamond)
        if robot then
            cur_robot_num = cur_robot_num + 1
            --进桌
            local status,result = skynet.pcall(skynet.call, table_service, "lua", "entertable", robot.rid, robot.roledata, {}, true)
            ----filelog.sys_error("---------robotmgr.add_robot_to_table---------", rid, status, result)
            if status and result.retcode == nil then
                robot_list[robot.rid] = table_service
                robotmgr.create_robotpool[robot.rid].table_address = table_service
            else
                robotmgr.remove_robot(robot.rid)
            end
        end
    end
end

--通知机器人抢红包
function robotmgr.do_qhb(rids)
    if not rids or next(rids) == nil then return end
    local function robot_qhb(rid)
        local robot_data = robotmgr.create_robotpool[rid]
        if robot_data then
            local msgbody = {
                action_type = 1,
                hb_total_money = 0,
                landmine_num = 0,
            }
            local status, result = skynet.pcall(skynet.call, robot_data.table_address, "lua", "doaction", robot_data.rid, robot_data.roledata, msgbody)
        end
    end
    for index, rid in ipairs(rids) do
        skynet.fork(robot_qhb, rid)
    end
end

function robotmgr.do_qhb_nolimit(qhb_players)
    if not qhb_players or next(qhb_players) == nil then return end
    local function robot_qhb_nolimit(qhb_player)
        local robot_data = robotmgr.create_robotpool[qhb_player.rid]
        if robot_data then
            local msgbody = {
                action_type = 1,
                hb_total_money = 0,
                hb_id = qhb_player.hb_id,
            }
            local status, result = skynet.pcall(skynet.call, robot_data.table_address, "lua", "doaction", robot_data.rid, robot_data.roledata, msgbody)
        end
    end
    for index, qhb_player in ipairs(qhb_players) do
        skynet.fork(robot_qhb_nolimit, qhb_player)
    end
end

---通知机器人发红包
function robotmgr.do_ml(buryrids, hb_nums)
    if not buryrids or next(buryrids) == nil then return end
    local function robot_ml(rid, bury_money, hb_nums)
        local robot_data = robotmgr.create_robotpool[rid]
        if robot_data then
            local msgbody = {
                action_type = 2,
                hb_total_money = bury_money,
                landmine_num = base.get_random(1,9),
                hb_nums = hb_nums,
                bury_hb_num = 1,
            }
            local status, result =  skynet.pcall(skynet.call, robot_data.table_address, "lua", "doaction", robot_data.rid, robot_data.roledata, msgbody)
        end
    end

    for index, bury  in ipairs(buryrids) do
        skynet.fork(robot_ml, bury.rid, bury.bury_money, hb_nums)
    end
end

----无限模式通知机器人发红包
function robotmgr.do_ml_nolimit(bury_players)
    if not bury_players or next(bury_players) == nil then return end
    local function robot_ml_nolimit(rid, bury_info)
        local robot_data = robotmgr.create_robotpool[rid]
        if robot_data then
            --[[
            message doaction {
                optional int32 action_type      = 1; //操作类型 (1抢红包 2申请埋雷)
                optional int32 hb_total_money   = 2; // 红包金额
                optional int32 landmine_num     = 3; // 雷号
                optional int32 bury_hb_num      = 4; // 一次操作埋雷个数(无限模式使用)
                optional int32 hb_nums          = 5; // 一个雷中有几个包(无限模式使用，可以是7包和10包)
                optional string hb_id           = 6; // 红包id(无限模式使用)
            }
            --]]
            local hb_nums_pool = {7, 10}
            local msgbody = {
                action_type = 2,
                hb_total_money = bury_info.bury_money,
                landmine_num = base.get_random(1,9),
                hb_nums = hb_nums_pool[base.get_random(1,2)],
                bury_hb_num = bury_info.bury_num,
            }
            local status, result = skynet.pcall(skynet.call, robot_data.table_address, "lua", "doaction", robot_data.rid, robot_data.roledata, msgbody)
        end
    end
    for index, bury_info in ipairs(bury_players) do
        skynet.fork(robot_ml_nolimit, bury_info.rid, bury_info)
    end
end

function robotmgr.do_cancel_bury(cancel_bury_rids)
    if not cancel_bury_rids or next(cancel_bury_rids) == nil then return end
    local function cancel_bury(rid)
        local robot_data = robotmgr.create_robotpool[rid]
        if robot_data then
            local msgbody = {
                action_type = 3,
                hb_total_money = 0,
                landmine_num = 0,
            }
            local status, result = skynet.pcall(skynet.call, robot_data.table_address, "lua", "doaction", robot_data.rid, robot_data.roledata, msgbody)
        end
    end

    for index, rid in ipairs(cancel_bury_rids) do
        skynet.fork(cancel_bury, rid)
    end
end

function robotmgr.robot_balance(rid, changevalue, base_diamond)
    local robot_data = robotmgr.create_robotpool[rid]
    if not robot_data then return end
    robot_data.roledata.money.diamond = robot_data.roledata.money.diamond + changevalue
    robot_data.roledata.already_game_num = robot_data.roledata.already_game_num + 1

    -- local is_leave = skynet.call(".slotmgr", "lua", "get_can_leveltable", robot_data.roledata.already_game_num)
    -- filelog.sys_error("---------is_leave-----------", rid, robot_data.roledata.already_game_num, is_leave, robot_data.roledata.info.rolename)
    -- if is_leave == true then
    --     local msgbody = {}
    --     local status, result = skynet.pcall(skynet.call, robot_data.table_address, "lua", "leavetable", robot_data.rid, robot_data.roledata, msgbody)
    --     filelog.sys_error("-------status, result-------", rid, is_leave, robot_data.rid, result)
    --     robotmgr.delete_robot(rid)
    -- end
    ---filelog.sys_error("----robot_data.roledata.already_game_num -----", rid, robot_data.roledata.already_game_num )

    -- if robot_data.roledata.already_game_num == 30 then  ---50
    --     local get_temp = base.get_random(1,100)
    --     if get_temp <= 50 then
    --         robotmgr.remove_robot(rid)
    --     end
    -- elseif robot_data.roledata.already_game_num == 40 then  ---90 
    --     local get_temp = base.get_random(1,100)
    --     if get_temp <= 90 then
    --         robotmgr.remove_robot(rid)
    --     end
    -- elseif robot_data.roledata.already_game_num >= 50 then ---100
    --     robotmgr.remove_robot(rid)
    -- end
end

function robotmgr.check_robot_leave(rids)
    if not rids or next(rids) == nil then return end

    local function check_robotleave(rid)
        local robot_data = robotmgr.create_robotpool[rid]
        if not robot_data then return end
        local is_leave = skynet.call(".slotmgr", "lua", "get_can_leveltable", robot_data.roledata.already_game_num)
        --filelog.sys_error("---------is_leave-----------", rid, robot_data.roledata.already_game_num, is_leave, robot_data.roledata.info.rolename)
        if is_leave == true then
            local msgbody = {}
            local status, result = skynet.pcall(skynet.call, robot_data.table_address, "lua", "leavetable", robot_data.rid, robot_data.roledata, msgbody)
            --filelog.sys_error("-------status, result-------", rid, is_leave, robot_data.rid, result)
            robotmgr.delete_robot(rid)
        end
    end

    for _, rid in pairs(rids) do
        skynet.fork(check_robotleave, rid)
    end
end


function robotmgr.robot_leave_table(rids)
    if not rids or next(rids) == nil then return end
    local function robot_leavetable(rid)
        local robot_data = robotmgr.create_robotpool[rid]
        if not robot_data then return end
        local msgbody = {}
        local status, result = skynet.pcall(skynet.call, robot_data.table_address, "lua", "leavetable", robot_data.rid, robot_data.roledata, msgbody)
        --filelog.sys_error("-------status, result-------", rid, is_leave, robot_data.rid, result)
        robotmgr.delete_robot(rid)
    end

    for _, rid in pairs(rids) do
        skynet.fork(robot_leavetable, rid)
    end
end

--移除一个机器人
function robotmgr.remove_robot(rid)
    if not robot_list[rid] then
        return
    end

    --在桌子内，让机器人离桌
    if robot_list[rid] ~= 0 then
        local status, result = skynet.pcall(skynet.call, robot_list[rid], "lua", "leavetable", rid, {}, {})   --尝试离桌
        if not status then
            robotmgr.delete_robot(rid)
        else
            if not result or result.retcode ~= nil then
                skynet.send(robot_list[rid], "lua", "delay_leave", rid, {}, {})   --延迟离开，本局结束再离桌
            end
        end
    else
        robotmgr.delete_robot(rid)
    end
end

function robotmgr.delete_robot(rid)
    if robot_list[rid] then
        robot_list[rid] = nil
        cur_robot_num = cur_robot_num - 1
        table.insert( robotmgr.robotpool, robotmgr.robotinfo_list[rid])
        robotmgr.create_robotpool[rid] = nil
        robotmgr.robotinfo_list[rid] = nil
    end
end

--移除一些机器人
function robotmgr.remove_robots(rids, num)
    num = num or #rids

    --低于最小机器人数，不离桌
    if cur_robot_num - num < robotmgr.min_robot_num then
        num = cur_robot_num - robotmgr.min_robot_num
    end

    if num <= 0 then
        return
    end

    local cnt = 0
    for _,rid in pairs(rids) do
        robotmgr.remove_robot(rid)
        cnt = cnt + 1
        if cnt == num then
            break
        end
    end
end

--移除所有机器人
function robotmgr.remove_allrobot(is_force)
    if is_force then
        for rid,v in pairs(robot_list) do
            robotmgr.delete_robot(rid)
        end
    else
        for rid,v in pairs(robot_list) do
            robotmgr.remove_robot(rid)
        end
    end
end


-------------CMD FUNCTION-------------
function robotmgr.CMD.get_table_robot_num()
    return robotmgr.table_robot_num
end

function robotmgr.CMD.get_robot_runstate()
    return robotmgr.is_runrobot
end

--获得机器人数目
function robotmgr.CMD.get_game_robot_num()
    -- filelog.sys_error("------------robotmgr.CMD.get_game_robot_num---------", timetool.get_time(), cur_robot_num, #robotmgr.robotpool,
    --     robot_list, robotmgr.robotinfo_list, robotmgr.create_robotpool)
    return cur_robot_num
end

function robotmgr.CMD.game_end()
    for rid, robotlist in pairs(robot_list) do
        robotmgr.delete_robot(rid)
    end
    robotmgr.handler.save_robotinfos()
end

--设置机器人状态
function robotmgr.CMD.set_game_robot_state(is_run)
    if is_run then
        if robotmgr.is_runrobot == false then
            -----告诉所有桌子服务,开启了机器人
            skynet.send(".router", "lua", "notice_alltable_robot_open")
        end
        robotmgr.is_runrobot = true
    else
        robotmgr.is_runrobot = false
        --踢掉所有机器人
        robotmgr.remove_allrobot()
    end
end


function robotmgr:init()
	skynet.fork(function()
		local status = robotmgr.handler.gen_robotinfo(50)
		while(status == false) do
			skynet.sleep(20)
			status = robotmgr.handler.gen_robotinfo(50)
		end
	end)
end

function robotmgr:start()
	skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = robotmgr.CMD[cmd]
        if f then
            skynet.retpack(f(...))
        elseif robotmgr.is_runrobot then
            f = robotmgr[cmd]
            if f then
                skynet.retpack(f(...))
            else
                skynet.retpack()
            end
        else
            skynet.retpack()
        end
    end)
end

skynet.start(function() 
    robotmgr:start()
    robotmgr:init()
end)